package com.hx.service.impl;
import	java.util.HashMap;

import com.hx.bean.User;
import com.hx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {
    /**
     * 通过key获取值
     *
     * @param key
     * @return
     */
    @Autowired
    RedisTemplate<String, String> redisTemplate;
    @Resource(name = "redisTemplate")
    HashOperations<String, String, User> hash;

    @Resource(name = "redisTemplate")
    ValueOperations<String, String> string;
    @Resource(name = "redisTemplate")
    ListOperations<String, String> list;

    @Override
    public String getString(String key) {
        ValueOperations<String, String> string = redisTemplate.opsForValue();
        if (redisTemplate.hasKey(key)) {
            System.out.println("在redis中取出并返回");
            return string.get(key);
        } else {
            String result = "Redis模板练习";
            string.set(key, result);
            System.out.println("在数据库中取出并返回");
            return result;
        }

    }
    //#####################TODO  RedisTemplate针对Hash案例

    /**
     * 存储 往Redis中存储HASH数据
     */
    @Override
    public void add(User u) {
        //redisTemplate.opsForHash().put(User.getName(),u.getId(),u);
        hash.put(User.getName(), String.valueOf(u.getId()), u);
    }

    @Override
    public User selectById(String id) {
        //1 先判断Redis中是否存在该key，如果存在，从redis中取出，并返回即可
        if (redisTemplate.opsForHash().hasKey("user", id)) {
            //User user = (User) redisTemplate.opsForHash().get("user", id);
            User user = hash.get(User.getName(), id);
            System.out.println("redis中查询的对象");
            return user;
        } else {
            //如果不存在，则从数据库中取出赋给Redis，并返回
            User u = new User();
            u.setId(Integer.valueOf(id));
            u.setAge(23);
            u.setName("李晟");
            u.setUsername("admin");
            u.setPassword("123456");
            //redisTemplate.opsForHash().put(User.getName(),u.getId(),u);
            hash.put(User.getName(), String.valueOf(u.getId()), u);
            System.out.println("mysql数据库中查询的对象");
            return u;
        }


    }
    //#############3TODO list类型

    /**
     * redistemplate list 类型的存取
     */
    @Override
    public void listAdd() {
        String key = "news:top10";
//        list.leftPush(key,"新闻1");
//        list.leftPush(key,"aaa");
//        list.leftPushAll(key,"bbb","vvvv","dddd");
        list.rightPushAll(key, "1", "2", "3", "4asaad", "5dwfe", "6", "7", "8", "9");

    }

    @Override
    public List<String> listRange(int pageNum, int pageSize) {
        String key = "news:top10";

        List<String> range = list.range(key, (pageNum - 1) * pageSize, pageSize * pageNum - 1);
        return range;
    }

    @Override
    public User login(String uname, String pwd) {
        return null;
    }


    @Override
    public String loginValdate(String umane) {
        String key = User.getLoginCountFailKey(umane);
        //登录错误的测试
        int num = 5;
        if (!redisTemplate.hasKey(key)) {
            //如果不存在
            //是第一次登录失败次数为1赋值为1和设置失效2分钟 user:loginCount:fail:用户名 进行赋值，同时设置失效期
            //注意redisTemllate中在赋值时不能直接设置失效期（会设置失败）
            //先赋值
            redisTemplate.opsForValue().set(key, "1");
            //再设置失效期2分钟
            redisTemplate.expire(key, 2, TimeUnit.MINUTES);
            return "登录失败，当前还允许输入错误" + (num - 1) + "次";
        } else {
            //如果存在
            //查询登录失败次数的key结果
            long loginFailCount = Long.parseLong(redisTemplate.opsForValue().get(key));
            if (loginFailCount < (num - 1)) {
                //代表如果当前登录失败次数<4时，还有资格继续进行登录
                //user:loginCount；fail: +1 登录次数+1
                //对指定key增加指定数据
                redisTemplate.opsForValue().increment(key, 1);
                //返回的是秒
                Long seconds = redisTemplate.getExpire(key, TimeUnit.SECONDS);
                return "登录失败，在" + seconds + "秒内还允许错误" + (num - loginFailCount - 1) + "次";
            } else {//超过指定登录次数
                //限制登录KEY存在，同时设置限制登录时间锁定1小时
                redisTemplate.opsForValue().set(User.getLoginTimeLockKet(umane), "1");
                redisTemplate.expire(User.getLoginTimeLockKet(umane), 1, TimeUnit.HOURS);
                return "因登录失败次数超过限制" + num + "次，已对其限制登录1小时";
            }
        }

    }

    @Override
    public Map<String, Object> loginUserLock(String uname) {
        Map<String, Object> map = new HashMap<String, Object>();
        String key = User.getLoginTimeLockKet(uname);
        if (redisTemplate.hasKey(key)) {
            long lockTime = redisTemplate.getExpire(key, TimeUnit.MINUTES);
            map.put("flag", true);
            map.put("lockTime", lockTime);
        } else {
            map.put("flag", false);
        }
        return map;
    }

    //###############TODO 定单流程示例
    /**
     * 1付款完成后，会根据用户的收货地址和商家发货地址生产一个队列（任务)
     */
    @Override
    public void listQueueinit(String cardId){
        //初始化的key,待有多少任务要完成
        String key = "prid:" + cardId;
        list.leftPushAll(key,"1商家出货","2小哥发件","3小区--》机场","4北京机场=》武汉机场","5机场=》小区","6小区=》本人");
    }
    //2触发事件
    @Override
    public void listQueueTouch(String cardId){
        //已完成的任务列表key
        String key = "prid:" + cardId +":succ";
        list.rightPopAndLeftPush("prid:"+cardId,key);
    }
    @Override
    //3,查询：客户查询，我的快递到哪了
    public List<String> listQueueSucc(String cardId){
        //已完成的任务列表key
        String key = "prid:" + cardId +":succ";
        return list.range(key,0,-1);
    }


    //４　物流查询：当前还有多少任务没执行
    @Override
    public List<String> listQueueWait(String cardId){
        //待有多少任务要完成
        String key = "prid:" + cardId;
        return list.range(key,0,-1);
    }

}
